package com.one.blocks.mvc.exception;

import lombok.extern.slf4j.Slf4j;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.web.servlet.View;
import org.springframework.web.util.HtmlUtils;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.Date;
import java.util.Map;

/**
 * @author <a href="mailto:idler41@163.con">linfuxin</a> created on 2023-12-09 10:43:51
 */
@Slf4j
public class JsonView implements View {

    private final HttpServletRequest request;
    private final HttpStatus status;
    private final Map<String, Object> model;

    public JsonView(HttpServletRequest request, HttpStatus status, Map<String, Object> model) {
        this.request = request;
        this.status = status;
        this.model = model;
    }

    @Override
    public void render(Map<String, ?> modelMap, HttpServletRequest request, HttpServletResponse response) throws Exception {
        if (response.isCommitted()) {
            String message = getMessage(this.model);
            log.error(message);
            return;
        }
        response.setContentType(MediaType.APPLICATION_JSON_UTF8.toString());
        // TODO 参考StaticView, 为什么要重复设置？
        if (response.getContentType() == null) {
            response.setContentType(getContentType());
        }
        Date timestamp = (Date) this.model.get("timestamp");
        Object message = this.model.get("message");
        log.warn("未捕获异常!path={},visitTime={},type={},status={},msg={},trace={}", this.model.get("path"),
                this.model.get("visitTime"), this.model.get("type"), this.model.get("status"), this.model.get("msg"), this.model.get("trace"));
        String builder = "{" +
                "\"result\":\"error\"," +
                "\"path\":\"" + this.model.get("path") + "\"," +
                "\"visitTime\":\"" + timestamp + "\"," +
                "\"type\":\"" + htmlEscape(this.model.get("error")) + "\"," +
                "\"status\":\"" + htmlEscape(this.status.toString()) + "\"," +
                "\"msg\":\"" + htmlEscape(message) + "\"" +
                "}";
        response.getWriter().append(builder);
    }

    @Override
    public String getContentType() {
        return MediaType.APPLICATION_JSON_UTF8.toString();
    }

    private String getMessage(Map<String, ?> model) {
        Object path = model.get("path");
        String message = "Cannot render error page for request [" + path + "]";
        if (model.get("message") != null) {
            message += " and exception [" + model.get("message") + "]";
        }
        message += " as the response has already been committed.";
        message += " As a result, the response may have the wrong status code.";
        return message;
    }

    private String htmlEscape(Object input) {
        return (input != null) ? HtmlUtils.htmlEscape(input.toString()) : null;
    }
}
